/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.server.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;

import com.sinai.mshab.client.ui.Key;

/**
 * This class provides a convenient way to create safe SQL insert queries. This
 * class utilizes {@link PreparedStatement} to insure that user input is made
 * safe. Furthermore, the class automates SQL creation and allows programmers to
 * avoid writing SQL that depends on a single database schema as the SQL query
 * can be made dynamically.
 * 
 * @author Arthur Kalmenson
 */
public class SQLInsert extends SQLObject {

	/**
	 * The name of table where information should be inserted.
	 */
	private String tableName;

	/**
	 * Creates a new SQLInsert object that utilizes the {@link Connection} conn
	 * and sets this SQLInsert's table name to tableName. conn and tableName
	 * must be instantiated and tableName cannot be null or an
	 * {@link IllegalArgumentException} will be thrown.
	 * 
	 * @param conn
	 *            the connection to the database.
	 * @param tableName
	 *            the database table where information will be entered.
	 */
	public SQLInsert(Connection conn, String tableName) {
		super.connection = conn;

		if (super.invalidArgument(tableName)) {
			throw new IllegalArgumentException(
					"The table name must be instantiated and not empty");
		} else {
			this.tableName = tableName;
		}
	}

	public void add(String fieldName, String value) {
		super.add(tableName, fieldName, value);
	}
	
	public void add(Key dbKeys) {
		super.add(dbKeys);
	}

	public PreparedStatement getPreparedStatement() throws SQLException {
		PreparedStatement insert = null;

		if (dbFields == null || dbFields.isEmpty()) {
			return insert;
		}

		// start the insert sql.
		String sql = "INSERT INTO " + tableName + " ";

		sql += createInsertFields();
		sql += " VALUES ";
		sql += createInsertUnknowns();

		insert = connection.prepareStatement(sql);

		int fillIndex = 1;

		// fill in the values.
		fillUnknowns(insert, dbFields, fillIndex);

		return insert;
	}

	public int execute() throws SQLException {
		return super.executeUpdate();
	}

	/**
	 * Returns the SQL segment in an INSERT statement that contains the field
	 * names enclosed in parenthesis.
	 * 
	 * @return the SQL segment in an INSERT statement that contains the field
	 *         names enclosed in parenthesis.
	 */
	private String createInsertFields() {
		String sql = "(";

		Iterator fields = dbFields.iterator();

		int i = 0;
		while (fields.hasNext()) {
			DbField field = (DbField) fields.next();
			sql += " " + field.getField();

			// if we're not in the last section, add a comma
			if (i != dbFields.size() - 1) {
				sql += ",";
			}
			i++;
		}

		sql += " )";

		return sql;
	}

	/**
	 * Returns the SQL segment in an INSERT statement which maps to the field
	 * names. Essentially it includes question marks enclosed in parenthesis.
	 * This section will be filled in by the {@link PreparedStatement}.
	 * 
	 * @return the SQL segment in an INSERT statement which maps to the field
	 *         names.
	 */
	private String createInsertUnknowns() {

		String sql = "(";

		for (int i = 0; i < dbFields.size(); i++) {
			sql += " ?";

			// if we're not in the last section, add a comma
			if (i != dbFields.size() - 1) {
				sql += ",";
			}
		}
		sql += " )";

		return sql;
	}
}
